﻿using ServerListerner.Connections;
using ServerListerner.Helper;

using System;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Sockets;
using System.Reflection;

namespace ServerListerner.Server
{
    public class UDPServer : ServerConnect, IUDPServer
    {
        private readonly Socket _socket;
        private IPAddress address;
        private readonly int _port;
        private Action<IUDPConnection>? _action;
        private IUDPConnection? _connection;
        public UDPServer(int port)
        {
            _port = port;
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _socket.EnableBroadcast = true;
        }
        public UDPServer(IPAddress? ip, int port) : this(port)
        {
            address = ip ?? IPAddress.Any;
        }
        public UDPServer(string? ip, int port) : this(IPAddress.Parse(ip ?? "0.0.0.0"), port) { }

        public bool StartListen(Action<IUDPConnection> action)
        {
            try
            {
                if (_port.PortInUse(false))
                    return false;
                _action = action;
                address = address ?? IPAddress.Any;
                _socket.Bind(new IPEndPoint(address, _port));
                StartAccept();
                return _port.PortInUse(false);
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        public void ClientSend(EndPoint Point, byte[] bytes) {
            _connection?.Send(Point, bytes);
        }
        public void ClientSend(IPAddress iP, int port, byte[] bytes)
        {
            _connection?.Send(iP, port, bytes);
        }
        public void ClientSend(string iP, int port, byte[] bytes)
        {
            _connection?.Send(iP, port, bytes);
        }
        public bool StopListen()
        {
            _connection?.Dispose();
            CloseSocket();
            return !_port.PortInUse(false);
        }
        private void StartAccept()
        {
            _connection = StartConnection<IUDPConnection>(new object[] { _socket, _action });// new UDPConnection(this._socket, this._action);
        }
        public void Dispose()
        {
            StopListen();
            _action = null;
        }
        private void CloseSocket()
        {
            if (_socket.Connected)
                _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();
            _socket.Dispose();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }
}